# technology_manager.gd
extends Node

# ======================================================
# 科技管理器
# 负责加载、管理和查询科技资源
# ======================================================

#region 属性
# ------------------------------------------------------
# 配置品质权重（数组形式[COMMON, RARE, EPIC, LEGENDARY]）
var _quality_weights = {
								  1: [100, 0, 0, 0], # 等级1
								  2: [83, 10, 5, 2], # 100-17=83 | 0+10=10 | 0+5=5 | 0+2=2
								  3: [66, 20, 10, 4], # 83-17=66 | 10+10=20 | 5+5=10 | 2+2=4
								  4: [49, 30, 15, 6], # 继续应用增量
								  5: [32, 40, 20, 8],
								  6: [15, 50, 25, 10],
								  7: [0, 58, 30, 12], # 15-17=-2 → 调整为0，差额-2加到RARE（50+10-2=58）
								  8: [0, 51, 35, 14], # 58+10=68 | 30-5=25（因COMMON=0无法减，差额处理）
								  9: [0, 44, 40, 16], # 继续调整分配
								  10: [0, 37, 45, 18] # 最终需要手动修正为[0, 85, 15, 0]保持有效值
							  }

# 缓存科技实例（Quality => Array[TechnologyBase]）
var _tech_cache: Dictionary = {}
# 初始化标记
var _initialized := false
# 单例
#endregion

#region 初始化方法
# ------------------------------------------------------
func _ready() -> void:
	_initialize()

# 动态加载科技脚本
func _initialize():
	"""
	初始化科技管理器，加载所有科技脚本并缓存。
	确保只初始化一次。
	"""
	if _initialized:
		return

	# 初始化品质分类
	for quality in GameConstant.QUALITY.values():
		_tech_cache[quality] = []

	# 扫描目录
	var dir_path = "res://game/02_scripts/effect/technology_resource/"
	var dir = DirAccess.open(dir_path)

	if not dir:
		push_error("科技目录不存在: " + dir_path)
		return

	dir.list_dir_begin()
	var file_name = dir.get_next()

	while file_name != "":
		if file_name.ends_with(".gd"):
			var script_path = dir_path.path_join(file_name)
			_load_tech_script(script_path)
		file_name = dir.get_next()

	_initialized = true


# 加载单个科技脚本
func _load_tech_script(path: String):
	"""
	加载单个科技脚本并验证其有效性，然后将其缓存。
	@param path: 科技脚本的路径
	"""
	# 加载脚本
	var script = load(path)
	if not script:
		push_error("加载科技脚本失败: " + path)
		return

	# 验证继承关系
	if not script.is_class("GDScript"):
		push_error("无效科技脚本: " + path)
		return

	# 实例化并验证
	var _instance = script.new()
	if not _instance is TechnologyResource:
		push_error("科技类未继承TechnologyResource: " + path)
		_instance.free()
		return

	# 验证品质有效性
	if not _instance.quality in GameConstant.QUALITY.values():
		push_error("无效品质设置: %s (%s)" % [path, _instance.quality])
		_instance.free()
		return

	# 加入缓存
	_tech_cache[_instance.quality].append(_instance)
#endregion

#region 获取随机科技
# ------------------------------------------------------
func get_random_technologies(level: int, count: int) -> Array:
	"""
	根据给定的等级和数量获取随机科技。
	@param level: 科技等级
	@param count: 需要获取的科技数量
	@return: 包含随机科技实例的数组
	"""
	_initialize()
	var effective_level = clamp(level, 1, 10)
	var weights = _get_current_weights(effective_level)
	
	# 获取已拥有科技的ID集合
	var owned_techs := {}
	for tech in GameData.army_data.technologies:
		owned_techs[tech.tech_id] = true
	
	# 第一步：选择目标品质
	var quality_index = GameManager.rng.rand_weighted(weights)
	var target_quality = GameConstant.QUALITY.values()[quality_index]
	
	# 收集所有可用科技（按品质分类）
	var available_techs := {}
	for quality in _tech_cache:
		var techs = _tech_cache[quality].filter(
			func(t): return not owned_techs.has(t.tech_id)
		)
		if not techs.is_empty():
			available_techs[quality] = techs.duplicate()
	
	# 分阶段选择
	var selected = []
	
	# 阶段1：优先从目标品质选择
	if available_techs.has(target_quality):
		var target_pool = available_techs[target_quality]
		var take_num = min(count, target_pool.size())
		selected += _random_select(target_pool, take_num)
		available_techs.erase(target_quality)
	
	# 阶段2：从剩余品质补充
	if selected.size() < count:
		var remaining = count - selected.size()
		var mixed_pool = []
		for quality in available_techs:
			mixed_pool += available_techs[quality]
		
		if mixed_pool.size() >= remaining:
			selected += _random_select(mixed_pool, remaining)
		else:
			selected += mixed_pool
			# 阶段3：补充空科技
			for i in range(remaining - mixed_pool.size()):
				selected.append(_create_empty_tech())
	
	return selected.slice(0, count)

# 辅助方法：从数组中随机选择指定数量（不重复）
func _random_select(pool: Array, count: int) -> Array:
	"""
	从给定的数组中随机选择指定数量的元素，确保不重复。
	@param pool: 源数组
	@param count: 需要选择的元素数量
	@return: 包含随机选择元素的数组
	"""
	if pool.is_empty() or count <= 0:
		return []
	
	# 直接处理全选情况
	if count >= pool.size():
		return pool.duplicate()

	# 优化版部分洗牌算法
	var n = pool.size()
	var indexes = range(n)
	var selected = []
	
	for i in range(count):
		# 生成剩余范围内的随机索引
		var rand_idx = GameManager.rng.randi_range(i, n - 1)
		# 交换保持剩余池随机性（使用临时变量）
		var temp = indexes[i]
		indexes[i] = indexes[rand_idx]
		indexes[rand_idx] = temp
		selected.append(pool[indexes[i]])
	
	return selected


# 创建空科技占位符
func _create_empty_tech() -> TechnologyResource:
	"""
	创建一个空的科技占位符实例。
	@return: 空的TechnologyResource实例
	"""
	var empty = TechnologyResource.new()
	empty.tech_id = "empty_slot"
	empty.display_name = "Empty"
	empty.description = "empty technology"
	return empty

# 获取当前等级的权重配置（保持不变）
func _get_current_weights(level: int) -> Array:
	"""
	根据给定的等级获取对应的权重配置。
	@param level: 科技等级
	@return: 包含权重的数组
	"""
	var levels = _quality_weights.keys()
	levels.sort()
	var target_level = levels[0]

	for lv in levels:
		if lv <= level and lv > target_level:
			target_level = lv

	return _quality_weights[target_level]
#endregion

#region 数据查询扩展
# ------------------------------------------------------
func get_tech_by_id(tech_id: String) -> TechnologyResource:
	"""
	根据科技ID获取对应的科技实例。
	@param tech_id: 要查找的科技唯一标识符
	@return: TechnologyResource实例，如果找不到则返回null
	"""
	_initialize() # 确保完成初始化
	
	# 遍历所有品质层级的科技缓存
	for quality in _tech_cache:
		# 在当前品质层级中搜索匹配的科技
		for tech in _tech_cache[quality]:
			if tech.tech_id == tech_id:
				return tech
	# 未找到时返回空值
	return null

func get_all_technologies() -> Array[TechnologyResource]:
	"""
	获取所有已加载的科技实例。
	@return: 包含全部科技实例的数组（不包含动态生成的空槽位）
	"""
	_initialize() # 确保完成初始化
	
	var all_techs = []
	# 合并所有品质层级的科技
	for quality in _tech_cache:
		all_techs += _tech_cache[quality]
	return all_techs

func get_techs_by_quality(quality: int) -> Array[TechnologyResource]:
	"""
	获取指定品质的所有科技实例。
	@param quality: 品质枚举值（使用TechnologyResource.Quality中的定义）
	@return: 包含指定品质科技实例的数组副本，无效品质返回空数组
	"""
	_initialize() # 确保完成初始化
	
	# 验证品质有效性
	if not _tech_cache.has(quality):
		push_warning("请求了无效的品质层级: %d" % quality)
		return []
	
	# 返回副本以防止外部修改影响缓存
	return _tech_cache[quality].duplicate()
#endregion
